home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / CPPTASK.ARJ / TSKTASK.CPP < prev    next >
C/C++ Source or Header  |  1991-08-21  |  8KB  |  422 lines

  1. /*
  2.    CPPTask - A Multitasking Kernel For C++
  3.  
  4.    Version 1.0 08-12-91
  5.  
  6.    Ported by Rich Smith from:
  7.  
  8.    Public Domain Software written by
  9.       Thomas Wagner
  10.       Patschkauer Weg 31
  11.       D-1000 Berlin 33
  12.       West Germany
  13.  
  14.    TSKTASK.CPP - task class member functions
  15.  
  16.    Subroutines:
  17.         task::task
  18.         task::~task
  19.         task::operator new
  20.         task::start_task
  21.         task::wake_task
  22.         task::tsk_enqueue
  23.         task::tsk_unqueue
  24.         task::tsk_enqtimer
  25.         task::tsk_unqtimer
  26.         task::tsk_runable
  27.         task::set_priority
  28.         task::get_priority
  29.         task::set_state
  30.         task::get_state
  31.         task::set_user_flags
  32.         task::set_system_flags
  33.         task::get_flags
  34.         task::set_retptr
  35.         task::get_retptr
  36.         task::set_retsize
  37.         task::get_retsize
  38.         task::get_next
  39.  
  40. */
  41.  
  42. #include "task.hpp"
  43. #include "tsklocal.hpp"
  44.  
  45. /*
  46.    create_task
  47.       Initialises a tcb. The task is in stopped state initially.
  48. */
  49.  
  50. task::task (funcptr func,
  51.             byteptr stackptr,
  52.             word stksz,
  53.             word priority,
  54.             farptr arg)
  55. {
  56.    struct task_stack far *stk;
  57.  
  58.    if (func == NULL)
  59.       {
  60.       stkbot = NULL;
  61.       stack = NULL;
  62.       queue = &tsk_eligible;
  63.       state = ST_RUNNING;
  64.       flags = flags | F_CRIT;
  65.       }
  66.    else
  67.       {
  68.       stk = (struct task_stack far *)
  69.             (stackptr + stksz - sizeof (struct task_stack));
  70.       stk->r_ds = stk->r_es = tsk_dseg ();
  71.       stk->r_bp = 0;
  72.       stk->r_flags = tsk_flags ();
  73.       stk->retn = func;
  74.       stk->dummyret = killretn;
  75.       stk->arg = arg;
  76.  
  77.       stkbot = stackptr;
  78.       stack = (byteptr) stk;
  79.       queue = NULL;
  80.       state = ST_STOPPED;
  81.       }
  82.    next = NULL;
  83.    prior = initprior = priority;
  84.    timerq = new timer(0, NULL, TKIND_TASK, 0);
  85.    timerq->strucp = (farptr) this;
  86. }
  87.  
  88.  
  89. /*
  90.    ~task
  91.       Removes a task from the system.
  92.       CAUTION: The task control block may *not* be immediately re-used
  93.                if it was enqueued in the timer queue. Check for
  94.                task->timerq->tstate == TSTAT_IDLE before modifying
  95.                the tcb.
  96. */
  97.  
  98. task::~task (void)
  99. {
  100.    byte st;
  101.    CRITICAL;
  102.  
  103.    C_ENTER;
  104.  
  105.  
  106.    if (this != &main_tcb)
  107.    {
  108.       if ((st = state) != ST_RUNNING)
  109.          tsk_unqueue ();
  110.  
  111.       queue = NULL;
  112.       tsk_kill ();
  113.       if (st == ST_RUNNING)
  114.          {
  115.          tsk_current = NULL;
  116.          tasker.schedule ();
  117.          }
  118.    C_LEAVE;
  119.    }
  120. }
  121.  
  122.  
  123. void* task::operator new(size_t size)
  124. {
  125.    void *ptr;
  126.  
  127.    ptr = tsk_alloc(size);   // call protected memory allocation procedure
  128.  
  129.    if (ptr)
  130.      ((tcbptr) ptr)->flags = F_TEMP;
  131.  
  132.    return ptr;
  133. }
  134.  
  135.  
  136. /*
  137.    tsk_kill - mark task as killed.
  138. */
  139.  
  140. void far task::tsk_kill (void)
  141. {
  142.    state = ST_KILLED;
  143.  
  144.    // delete timerq element only if it is IDLE, otherwise mark it for
  145.    // deletion by the timer_main function
  146.  
  147.    if (timerq->tstate != TSTAT_IDLE)
  148.       {
  149.       timerq->tstate = (byte) TSTAT_REMOVE;
  150.       if (flags & F_TEMP)
  151.          timerq->tkind |= TKIND_TEMP;
  152.       }
  153.    else 
  154.       delete timerq;
  155.  
  156.    if (flags & F_STTEMP)
  157.       delete stack;
  158.  
  159. }
  160.  
  161.  
  162. /*
  163.    start_task
  164.       Starts a stopped task. Returns -1 if the task was not stopped.
  165. */
  166.  
  167. int far task::start_task (void)
  168. {
  169.    CRITICAL;
  170.  
  171.    if (state == ST_STOPPED)
  172.       {
  173.       state = ST_ELIGIBLE;
  174.       C_ENTER;
  175.       tsk_enqueue (&tsk_eligible);
  176.       C_LEAVE;
  177.       return 0;
  178.       }
  179.    return -1;
  180. }
  181.  
  182.  
  183. /*
  184.    wake_task
  185.       Restarts a task waiting for an event or timeout. 
  186.       Returns -1 if the task was not waiting or stopped.
  187. */
  188.  
  189. int far task::wake_task (void)
  190. {
  191.    CRITICAL;
  192.  
  193.    C_ENTER;
  194.    if (state >= ST_ELIGIBLE)
  195.       {
  196.       C_LEAVE;
  197.       return -1;
  198.       }
  199.  
  200.    retptr = TWAKE;
  201.    tsk_wakeup ();
  202.    C_LEAVE;
  203.    return 0;
  204. }
  205.  
  206.  
  207.  
  208. /*
  209.    get_priority
  210.       Returns the priority of a task.
  211. */
  212.  
  213. word far task::get_priority (void)
  214. {
  215.    return prior;
  216. }
  217.  
  218.  
  219. /*
  220.    set_priority
  221.       Changes the priority of a task. If the task is enqueued in a
  222.       queue, its position in the queue is affected.
  223. */
  224.  
  225. void far task::set_priority (word newprior)
  226. {
  227.    tqueptr que;
  228.    CRITICAL;
  229.  
  230.    C_ENTER;
  231.    prior = initprior = newprior;
  232.  
  233.    if ((state != ST_RUNNING) && ((que = queue) != NULL))
  234.       {
  235.       tsk_unqueue ();
  236.       tsk_enqueue (que);
  237.       }
  238.    C_LEAVE;
  239. }
  240.  
  241. /*
  242.    set_user_flags
  243.       Changes the user modifiable flags of the task.
  244. */
  245.  
  246. void far task::set_user_flags (byte newflags)
  247. {
  248.    CRITICAL;
  249.  
  250.    C_ENTER;
  251.    flags = (flags & FL_SYSM) | (newflags & FL_USRM);
  252.    C_LEAVE;
  253. }
  254.  
  255.  
  256. /*
  257.    set_system_flags
  258.       Changes the system modifiable flags of the task.
  259. */
  260.  
  261. void far task::set_system_flags (byte newflags)
  262. {
  263.    CRITICAL;
  264.  
  265.    C_ENTER;
  266.    flags = (newflags & FL_SYSM) | (flags & FL_USRM);
  267.    C_LEAVE;
  268. }
  269.  
  270.  
  271. /*
  272.    tsk_enqueue  inserts a task into a queue based on priority.
  273. */
  274.  
  275. void far task::tsk_enqueue (tqueptr que)
  276. {
  277.    tcbptr last, curr;
  278.  
  279.    last = NULL;
  280.    curr = *que;
  281.  
  282.    while (curr != NULL && curr->prior >= prior)
  283.       {
  284.       last = curr;
  285.       curr = curr->next;
  286.       }
  287.    next = curr;
  288.    if (last == NULL)
  289.       *que = this;
  290.    else
  291.       last->next = this;
  292.    queue = que;
  293. }
  294.  
  295.  
  296. /*
  297.    tsk_unqueue 
  298.       Removes a task from somewhere in the middle of a queue. It is only
  299.       used when stopping or prematurely waking a task, since in all other 
  300.       circumstances a task is only removed from the head of a queue.
  301. */
  302.  
  303. void far task::tsk_unqueue (void)
  304. {
  305.    tcbptr last, curr;
  306.  
  307.    if (state == ST_RUNNING || queue == NULL)
  308.       return;
  309.  
  310.    last = NULL;
  311.    curr = *queue;
  312.  
  313.    while (curr != this)
  314.       {
  315.       if (curr == NULL)
  316.          return;
  317.       last = curr;
  318.       curr = curr->next;
  319.       }
  320.  
  321.    if (last == NULL)
  322.       *queue = curr->next;
  323.    else
  324.       last->next = curr->next;
  325.    queue = NULL;
  326. }
  327.  
  328.  
  329. /*
  330.    tsk_enqtimer inserts a task into the timer queue.
  331. */
  332.  
  333. void far task::tsk_enqtimer (dword tout)
  334. {
  335.    tlinkptr curr;
  336.  
  337.    if (tout == 0)
  338.       return;
  339.  
  340.    /*
  341.       Tasks are not sorted in the timer queue, so the task is inserted
  342.       at the queue head. The timer task has to step through all tasks
  343.       in the queue to cont down the timeout, so sorting would not bring
  344.       any advantages.
  345.    */
  346.  
  347.    curr = timerq;
  348.    curr->timeout = tsk_timeout(tout);
  349.    if (curr->tstate == TSTAT_IDLE)
  350.       {
  351.       curr->next = tsk_timer;
  352.       tsk_timer = curr;
  353.       }
  354.    curr->tstate = TSTAT_COUNTDOWN;
  355. }
  356.  
  357.  
  358. /*
  359.    tsk_unqtimer marks task for removal from the timer queue.
  360. */
  361.  
  362. void task::tsk_unqtimer(void)
  363. {
  364.    if (timerq->tstate != TSTAT_IDLE)
  365.       timerq->tstate = (byte) TSTAT_REMOVE;
  366. }
  367.  
  368.  
  369. /*
  370.    tsk_runable
  371.       make a task eligible for running. The task is removed from the
  372.       timer queue and enqueued in the eligible queue. The old "next"
  373.       pointer of the tcb is returned. This assumes that the task
  374.       is removed from the head of a queue.
  375. */
  376.  
  377. tcbptr far task::tsk_runable (void)
  378. {
  379.    tcbptr nxt;
  380.  
  381.    nxt = next;
  382.    state = ST_ELIGIBLE;
  383.    tsk_unqtimer ();
  384.    tsk_enqueue (&tsk_eligible);
  385.    return nxt;
  386. }
  387.  
  388.  
  389. /*
  390.    tsk_wakeup
  391.       make a task eligible for running. The task is removed from the
  392.       timer queue and enqueued in the eligible queue. 
  393.       This routine assumes that the task is removed from the middle of
  394.       a queue.
  395. */
  396.  
  397. void far task::tsk_wakeup (void)
  398. {
  399.    state = ST_ELIGIBLE;
  400.    tsk_unqueue ();
  401.    tsk_unqtimer ();
  402.    tsk_enqueue (&tsk_eligible);
  403. }
  404.  
  405.  
  406. /*
  407.    tsk_wait - put current running task in wait state.
  408.               Note that the task is NOT enqueued in the respective queue
  409.               here, this is done by the scheduler based on the queue head
  410.               pointer. Only the timeout queue is affected directly.
  411. */
  412.  
  413. void far tsk_wait (tqueptr que, dword timeout)
  414. {
  415.    tsk_current->state = ST_WAITING;
  416.    tsk_current->queue = que;
  417.    tsk_current->tsk_enqtimer (timeout);
  418.    tasker.schedule ();
  419. }
  420.  
  421.  
  422.